// 享元模式 (flyweight) - 以时间换空间的优化模式
// 模特例子
// const Model = function (sex, underwear) {
//     this.sex = sex;
//     this.underware = underwear;
// }

// Model.prototype.takePhoto = function(){
//     console.log(`sex: ${this.sex}, underwear: ${this.underware}`);
// }

// for (let i = 0; i <= 50; i++) {
//     const maleModel = new Model('male', `underwear${i}`);
//     maleModel.takePhoto();
// }

// for (let j = 0; j <= 50; i++) {
//     const femaleModel = new Model('female', `underwear${i}`);
//     femaleModel.takePhoto();
// }

// with flyweight
const Model = function(sex) {
    this.sex = sex; // 内部状态
}

Model.prototype.takePhoto = function(){
    console.log(`sex: ${this.sex}, underwear: ${this.underwear}`);
}

const maleModel = new Model('male');
const femaleModel = new Model('female');

for (let i = 0; i <= 50; i++) {
    maleModel.underwear = `underwear${i}` // 外部状态
    maleModel.takePhoto();
}

for (let i = 0; i <= 50; i++) {
    femaleModel.underwear = `underwear${i}` // 外部状态
    femaleModel.takePhoto();
}
// 如何区分内部和外部状态
// 文件上传
// let id = 0;
// window.startUpload = function(uploadType, files) {
//     for (let i = 0; i < files.length; i++) {
//         const file = files[i];
//         const uploadObject = new Upload(uploadType, file.fileName, file.fileSize)
//         uploadObject.init(id++);
//     }
// }

// const Upload = function(uploadType, name, size) {
//     this.uploadType = uploadType; // 内部状态
//     this.fileName = name; // 外部状态
//     this.fileSize = size; // 外部状态
//     this.dom = null;
// }

// Upload.prototype.init = function() {
//     this.id = id;
//     this.dom = document.createElement('div');
//     this.dom.innerHTML = `
//         <span>文件名称: ${this.fileName}，文件大小: ${this.fileSize}</span>
//         <button class="delFile">删除</button>
//     `;
//     this.dom.querySelector('.delFile').onclick = function() {
//         this.delFile();
//     };
//     document.body.appendChild(this.dom);
// }

// Upload.prototype.delFile = function() {
//     if (this.fileSize < 3000) {
//         return this.dom.parentNode.removeChild(this.dom);
//     }
//     if (window.confirm('确定删除该文件?')) {
//         return this.dom.parentNode.removeChild(this.dom);
//     }
// }

// startUpload('plugin', [
//     { fileName: '1.txt', fileSize: 1000 },
//     { fileName: '2.txt', fileSize: 3000 },
//     { fileName: '3.txt', fileSize: 2000 }
// ])

// startUpload('flash', [
//     { fileName: '4.txt', fileSize: 1000 },
//     { fileName: '5.txt', fileSize: 3000 },
//     { fileName: '6.txt', fileSize: 2000 }
// ])

// upload with flyweight

const Upload = function(uploadType) {
    this.uploadType = uploadType;
}

// 单一的上传方式
// const Upload = function() {}

Upload.prototype.delFile = function() {
    uploadManager.setExternalState(id, this); // (1)
    if (this.fileSize < 3000) {
        return this.dom.parentNode.removeChild(this.dom);
    }
    if (window.confirm('确定删除该文件?')) {
        return this.dom.parentNode.removeChild(this.dom);
    }
}

const UploadFactory = (function() {
    const createdFlyWeightObjs = {};
    return {
        create: function(uploadType) {
            if (createdFlyWeightObjs[uploadType]) {
                return createdFlyWeightObjs[uploadType]
            }
            return createdFlyWeightObjs[uploadType] = new Upload(uploadType);
        }
    }
})()

// 单一的上传模式
// const UploadFactory = (function() {
//     let uploadObj;
//     return {
//         create: function() {
//             if (uploadObj) {
//                 return uploadObj;
//             }
//             return uploadObj = new Upload();
//         }
//     }
// })()


const uploadManager = (function () {
    const uploadDatabase = {};
    return {
        add: function(id, uploadType, fileName, fileSize) {
            const flyWeightObj = UploadFactory.create(uploadType);
            const dom = document.createElement('div');
            dom.innerHTML = `
                <span>文件名称: ${fileName}，文件大小: ${fileSize}</span>
                <button class="delFile">删除</button>
            `;
            dom.querySelector('.delFile').onclick = function() {
                flyWeightObj.delFile(id);
            };
            document.body.appendChild(dom);
            uploadDatabase[id] = {
                fileName,
                fileSize,
                dom
            }
            return flyWeightObj;
        },
        setExternalState: function(id, flyWeightObj) {
            const uploadData = uploadDatabase[id]
            for (let i in uploadData) {
                flyWeightObj[i] = uploadData[i]
            }
        }
    }
})()
let id = 0;
window.startUpload = function(uploadType, files) {
    for (let i = 0; i < files.length; i++) {
        const file = files[i];
        const uploadObject = uploadManager.add(++id, uploadType, file.fileName, file.fileSize);
    }
}
// 如何用&什么时候用
// 1. 大量的相似对象
// 2. 由1导致的内存开销
// 3. 外部状态居多
// 4. 剥离外部状态后，用相对少量的共享对象取代大量的相似对象


// javascript intern
const TooltipFactory = (function() {
    const tooltipPool = [];
    return {
        create: function() {
            if (tooltipPool.length === 0) {
                const div = document.createElement('div');
                document.body.appendChild(div);
                return div;
            } else {
                return tooltipPool.shift();
            }
        },
        recover: function(tooltipDOM) {
            return tooltipPool.push(tooltipDOM);
        }
    }
})();

const array = []
const strs = ['A', 'B']
for (let i = 0; i <= strs.length; i++) {
    const str = strs[i];
    const tooltip = TooltipFactory.create();
    tooltip.innerHTML = str;
    array.push(tooltip)
}

for (let j = 0; j <= array.length; j++) {
    TooltipFactory.recover(array[i]);
}

// 通过对象池
const objectPoolFactory = function(createObjectFn) {
    const objectPool = [];
    return {
        create: function() {
            const obj = objectPool.length === 0
                ? createObjectFn.apply(this, arguments)
                : objectPool.shift();
            return obj;
        },
        recover: function(obj) {
            objectPool.push(obj);
        }
    }
}

// 职责链
// 请求 -> A -> B -> C -> D
// 交定金的购买流程
// orderType 订单类型 1 -> 500 2 -> 200 3 -> 0
// pay 是否支付定金
// stock 0档库存
// const order = function(orderType, pay, stock) {
//     if (orderType === 1) {
//         if (pay) {
//             // 500定金 返100券
//         } else {
//             if (stock > 0 ) {
//                 // 购买
//             } else {
//                 // 买不了 库存不足
//             }
//         }
//     } else if (orderType === 2) {
//         if (pay) {
//             // 200定金 返40券
//         } else {
//             if (stock > 0 ) {
//                 // 购买
//             } else {
//                 // 买不了 库存不足
//             }
//         }
//     } else if (orderType === 3) {
//         if (stock > 0) {
//             // 能买
//         } else {
//             // 不能买
//         }
//     }
// }

// 职责链order
const order500 = function(orderType, pay, stock) {
    if (orderType === 1 && pay) {
        // 500定金 返100券
    } else {
        return 'nextProcessor'
    }
}

const order200 = function(orderType, pay, stock) {
    if (orderType === 2 && pay) {
        // 200定金 返40券
    } else {
        return 'nextProcessor'
    }
}

const orderNormal = function(orderType, pay, stock) {
    if (stock > 0) {
        // 能买
    } else {
        // 不能买
    }
}

const Chain = function (fn) {
    this.fn = fn;
    this.processor = null;
}

Chain.prototype.setNextProcessor = function(processor) {
    return this.processor = processor;
}

Chain.prototype.passRequest = function() {
    const ret = this.fn.apply(this, arguments);
    if (ret === 'nextProcessor') {
        return this.processor && this.processor.passRequest.apply(this.processor, arguments);
    }
    return ret;
}

Chain.prototype.next = function() {
    return this.processor && this.processor.passRequest.apply(this.processor, arguments);
}

// const chainOrder500 = new Chain(order500);
// const chainOrder200 = new Chain(order200);
// const chainOrderNormal = new Chain(orderNormal);

// chainOrder500.setNextProcessor(chainOrder200);
// chainOrder200.setNextProcessor(chainOrderNormal);

const fn1 = new Chain(function() {
    console.log('1');
    return 'nextProcessor'
})
const fn2 = new Chain(function() {
    console.log('2');
    const self = this;
    setTimeout(() => {
        self.next();
    }, 20);
})
const fn3 = new Chain(function() {
    console.log('3');
});
fn1.setNextProcessor(fn2).setNextProcessor(fn3);
fn1.passRequest();

// Function.prototype.after
Function.prototype.after = function(fn) {
    const self = this;
    return function() {
        const ret = self.apply(this, arguments);
        if (ret === 'nextProcessor') {
            return fn.apply(this, arguments);
        }
        return ret;
    }
}

const order = order500.after(order200).after(orderNormal);


// 适配器 -> wrapper

const googleMap = {
    show: function() {
        console.log('render');
    }
}

const amap = {
    display: function() {
        console.log('render');
    }
}

const amapAdapter = {
    show: function() {
        return amap.display();
    }
}

renderMap(googleMap);
renderMap(amapAdapter);


const getGuangdongCity = function() {
    const guangdongCity = [
        { city: 'shenzhen',id: 11 },
        { city: 'guangzhou', id: 12 }
    ];
    return guangdongCity;
}

const newData = {
    'shenzhen': 11,
    'guangzhou': 12,
    'zhuhai': 13
}

const addressAdapter = function(oldAddressFn){
    const address = {};
    const oldAddress = oldAddressFn();

    for (let i = 0; i <= oldAddress.length; i++) {
        const addressItem = oldAddress[i];
        address[addressItem.name] = addressItem.id;
    }
    return function() {
        return address
    }
}